package com.binhthuan.catechist.client.grid;

import java.util.Map;
import java.util.Vector;

import com.binhthuan.catechist.client.ECApplication;
import com.binhthuan.catechist.client.ECIcons;
import com.binhthuan.catechist.client.data.AbstractDS;
import com.binhthuan.catechist.shared.Utilities;
import com.google.gwt.event.shared.HandlerRegistration;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.SortDirection;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.ImgButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
import com.smartgwt.client.widgets.layout.HLayout;

public abstract class AbstractGrid extends ListGrid implements IGrid {

    private static final String ACTIONS_FIELD = "_actionsField";
    private HLayout rollOverCanvas;
    private ListGridRecord rollOverRecord;
    private boolean showDetailButton;
    private boolean showEditButton;
    private boolean showDeleteButton;
    private Vector<IGrid.ViewButtonClickHandler> viewButtonClickHandlers = new Vector<IGrid.ViewButtonClickHandler>();
    private Vector<IGrid.EditButtonClickHandler> editButtonClickHandlers = new Vector<IGrid.EditButtonClickHandler>();
    private Vector<IGrid.DeleteButtonClickHandler> deleteButtonClickHandlers = new Vector<IGrid.DeleteButtonClickHandler>();

    public AbstractGrid() {
        initGrid();
    }

    public AbstractGrid(AbstractDS dataSource) {
        setDataSource(dataSource);
        initGrid();
    }

    /**
     * 
     */
    public void initGrid() {
        setWidth100();
        setHeight100();
        setShowRowNumbers(true);
        setAlternateRecordStyles(true);
        setAutoFetchData(true);

        setLoadingDataMessage(ECApplication.getMessages().loadingData());
        if (initializeCriteria() != null) {
            setInitialCriteria(initializeCriteria());
        }
    }

    protected Criteria initializeCriteria() {
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.smartgwt.client.widgets.grid.ListGrid#createRecordComponent(com.smartgwt
     * .client.widgets.grid.ListGridRecord, java.lang.Integer)
     */
    @Override
    protected Canvas createRecordComponent(final ListGridRecord record, Integer colNum) {
        String fieldName = this.getFieldName(colNum);

        if (fieldName.equals(ACTIONS_FIELD)) {
            HLayout recordCanvas = new HLayout(5);
            recordCanvas.setHeight(22);
            recordCanvas.setSnapTo("TR");
            //recordCanvas.setWidth(50);
            recordCanvas.setAlign(Alignment.RIGHT);

            if (showDetailButton) {
                ImgButton detailImg = new ImgButton();
                detailImg.setShowDown(false);
                detailImg.setShowRollOver(false);
                detailImg.setLayoutAlign(Alignment.CENTER);
                detailImg.setSrc(ECIcons.getIcon("detail.png"));
                detailImg.setPrompt(ECApplication.getConstants().viewDetail());
                detailImg.setHeight(16);
                detailImg.setWidth(16);
                detailImg.addClickHandler(new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        onViewClick(record);
                    }
                });
                recordCanvas.addMember(detailImg);
            }

            if (showEditButton) {
                ImgButton editImg = new ImgButton();
                editImg.setShowDown(false);
                editImg.setShowRollOver(false);
                editImg.setLayoutAlign(Alignment.CENTER);
                editImg.setSrc(ECIcons.getIcon("edit.png"));
                editImg.setPrompt(ECApplication.getConstants().edit());
                editImg.setHeight(16);
                editImg.setWidth(16);
                editImg.addClickHandler(new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        onEditClick(record);
                    }
                });
                recordCanvas.addMember(editImg);
            }

            if (showDeleteButton) {
                ImgButton deleteImg = new ImgButton();
                deleteImg.setShowDown(false);
                deleteImg.setShowRollOver(false);
                deleteImg.setLayoutAlign(Alignment.CENTER);
                deleteImg.setSrc(ECIcons.getIcon("delete.png"));
                deleteImg.setPrompt(ECApplication.getConstants().delete());
                deleteImg.setHeight(16);
                deleteImg.setWidth(16);
                deleteImg.addClickHandler(new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        onDeleteClick(record);
                    }
                });
                recordCanvas.addMember(deleteImg);
            }

            return recordCanvas;
        }

        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.smartgwt.client.widgets.grid.ListGrid#getRollOverCanvas(java.lang
     * .Integer, java.lang.Integer)
     */
    @Override
    protected Canvas getRollOverCanvas(Integer rowNum, Integer colNum) {
        rollOverRecord = this.getRecord(rowNum);

        if (rollOverCanvas == null) {
            rollOverCanvas = new HLayout(5);
            rollOverCanvas.setSnapTo("TR");
            rollOverCanvas.setWidth(50);
            rollOverCanvas.setHeight(22);

            if (showDetailButton) {
                ImgButton detailImg = new ImgButton();
                detailImg.setShowDown(false);
                detailImg.setShowRollOver(false);
                detailImg.setLayoutAlign(Alignment.CENTER);
                detailImg.setSrc(ECIcons.getIcon("detail.png"));
                detailImg.setPrompt(ECApplication.getConstants().viewDetail());
                detailImg.setHeight(16);
                detailImg.setWidth(16);
                detailImg.addClickHandler(new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        onViewClick(rollOverRecord);
                    }
                });
                rollOverCanvas.addMember(detailImg);
            }

            if (showEditButton) {
                ImgButton editImg = new ImgButton();
                editImg.setShowDown(false);
                editImg.setShowRollOver(false);
                editImg.setLayoutAlign(Alignment.CENTER);
                editImg.setSrc(ECIcons.getIcon("edit.png"));
                editImg.setPrompt(ECApplication.getConstants().edit());
                editImg.setHeight(16);
                editImg.setWidth(16);
                editImg.addClickHandler(new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        onEditClick(rollOverRecord);
                    }
                });
                rollOverCanvas.addMember(editImg);
            }

            if (showDeleteButton) {
                ImgButton deleteImg = new ImgButton();
                deleteImg.setShowDown(false);
                deleteImg.setShowRollOver(false);
                deleteImg.setLayoutAlign(Alignment.CENTER);
                deleteImg.setSrc(ECIcons.getIcon("delete.png"));
                deleteImg.setPrompt(ECApplication.getConstants().delete());
                deleteImg.setHeight(16);
                deleteImg.setWidth(16);
                deleteImg.addClickHandler(new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        onDeleteClick(rollOverRecord);
                    }
                });
                rollOverCanvas.addMember(deleteImg);
            }
        }
        return rollOverCanvas;
    }

    /**
     * Click delete button when set <code>setShowDeleteButton(true)</code>
     * 
     * @param selectedRecord
     */
    protected void onDeleteClick(ListGridRecord selectedRecord) {
        for (DeleteButtonClickHandler handler : deleteButtonClickHandlers) {
            handler.onClick(selectedRecord);
        }
    }

    /**
     * Click edit button when set <code>setShowEditButton(true)</code>
     * 
     * @param selectedRecord
     */
    protected void onEditClick(ListGridRecord selectedRecord) {
        for (EditButtonClickHandler handler : editButtonClickHandlers) {
            handler.onClick(selectedRecord);
        }
    }

    /**
     * Click view detail button when set
     * <code>setShowViewDetailButton(true)</code>
     * 
     * @param selectedRecord
     */
    protected void onViewClick(ListGridRecord selectedRecord) {
        for (ViewButtonClickHandler handler : viewButtonClickHandlers) {
            handler.onClick(selectedRecord);
        }
    }

    @Override
    public void setSortDirection(SortDirection sortDirection) {
        setAttribute("sortDirection", sortDirection, true);
    }

    public int getSelectionItemsCount() {
        if (getSelection() != null) {
            return getSelection().length;
        }

        return 0;
    }

    public void removeSelectedItems(boolean showConfirmMsg) {
        if (!showConfirmMsg) {
            removeSelectedItems();
        } else {
            if (getSelectionItemsCount() == 0) {
                SC.warn(ECApplication.getMessages().requireSelectionToDeleteMessage());
            } else {
                SC.confirm(ECApplication.getMessages().deleteConfirmationMessage(), new BooleanCallback() {

                    @Override
                    public void execute(Boolean value) {
                        if (value) {
                            removeSelectedItems();
                        }
                    }
                });
            }
        }
    }

    protected void removeSelectedItems() {
        removeSelectedData(new com.binhthuan.catechist.client.data.callback.DSCallback() {

            @Override
            public void onSuccess() {
                removeItemsSuccess();
            }

            @SuppressWarnings("unchecked")
            @Override
            public void onFailure(DSResponse response, Object rawData) {
                boolean requireConfirm = response.getAttributeAsBoolean(AbstractDS.REQUIRE_CONFIRMATION) == null ? false
                        : response.getAttributeAsBoolean(AbstractDS.REQUIRE_CONFIRMATION);
                if (requireConfirm) {
                    deleteWithConfirmation(response.getErrors());
                } else {
                    removeItemsFailure(response.getErrors());
                }
            }
        }, null);
    }

    protected void removeItemsSuccess() {
        SC.say(ECApplication.getMessages().deleteSuccessMessage());
        fireEvent(new RecordClickEvent(null));
        fireEvent(new DataArrivedEvent(null));
    }

    protected void deleteWithConfirmation(Map<String, String> errors) {
        String msg = encodeErrorMessage(errors);
        if (!Utilities.isNullOrEmpty(msg)) {
            SC.ask(msg, new BooleanCallback() {

                @Override
                public void execute(Boolean value) {
                    if (value) {
                        DSRequest req = new DSRequest();
                        req.setAttribute(AbstractDS.REQUIRE_CONFIRMATION, true);
                        removeSelectedData(new com.binhthuan.catechist.client.data.callback.DSCallback() {

                            @Override
                            public void onSuccess() {
                                removeItemsSuccess();
                            }

                            @SuppressWarnings("unchecked")
                            @Override
                            public void onFailure(DSResponse response, Object rawData) {
                                removeItemsFailure(response.getErrors());
                            }
                        }, req);
                    }
                }
            });
            return;
        }
        SC.warn(ECApplication.getMessages().deleteFailureMessage());
    }

    protected void removeItemsFailure(Map<String, String> errors) {
        String msg = encodeErrorMessage(errors);
        if (!Utilities.isNullOrEmpty(msg)) {
            SC.warn(msg);
            return;
        }
        SC.warn(ECApplication.getMessages().deleteFailureMessage());
    }

    private String encodeErrorMessage(Map<String, String> errors) {
        if (errors.values().size() == 1) {
            return errors.values().toArray()[0].toString();
        }

        StringBuilder builder = new StringBuilder();
        for (Object err : errors.values().toArray()) {
            builder.append("- ").append(err.toString()).append("<br/>");
        }
        return builder.toString();
    }

    /**
     * @return the showViewDetailButton
     */
    public boolean getShowDetailButton() {
        return showDetailButton;
    }

    /**
     * @param showViewDetailButton
     *            the showViewDetailButton to set
     */
    public void setShowDetailButton(boolean showViewDetailButton) {
        this.showDetailButton = showViewDetailButton;
    }

    /**
     * @return the showEditButton
     */
    public boolean getShowEditButton() {
        return showEditButton;
    }

    /**
     * @param showEditButton
     *            the showEditButton to set
     */
    public void setShowEditButton(boolean showEditButton) {
        this.showEditButton = showEditButton;
    }

    /**
     * @return the showDeleteButton
     */
    public boolean getShowDeleteButton() {
        return showDeleteButton;
    }

    /**
     * @param showDeleteButton
     *            the showDeleteButton to set
     */
    public void setShowDeleteButton(boolean showDeleteButton) {
        this.showDeleteButton = showDeleteButton;
    }

    @Override
    public HandlerRegistration addDeleteButtonHandler(final DeleteButtonClickHandler handler) {
        assert deleteButtonClickHandlers != null;
        deleteButtonClickHandlers.add(handler);
        return new HandlerRegistration() {

            @Override
            public void removeHandler() {
                deleteButtonClickHandlers.remove(handler);
            }
        };
    }

    @Override
    public HandlerRegistration addEditButtonHandler(final EditButtonClickHandler handler) {
        assert editButtonClickHandlers != null;
        editButtonClickHandlers.add(handler);
        return new HandlerRegistration() {

            @Override
            public void removeHandler() {
                editButtonClickHandlers.remove(handler);
            }
        };
    }

    @Override
    public HandlerRegistration addViewButtonHandler(final ViewButtonClickHandler handler) {
        assert viewButtonClickHandlers != null;
        viewButtonClickHandlers.add(handler);
        return new HandlerRegistration() {

            @Override
            public void removeHandler() {
                viewButtonClickHandlers.remove(handler);
            }
        };
    }

    public void setShowActionsField(boolean showActionField) {
        setShowRecordComponents(showActionField);
        setShowRecordComponentsByCell(showActionField);
        if(showActionField) {
            ListGridField[] fields = getFields();
            ListGridField[] fs = new ListGridField[fields.length + 1];
            int idx = 0;
            for (ListGridField f : fields) {
                fs[idx++] = f;
            }
            ListGridField actionsField = new ListGridField(ACTIONS_FIELD, " ", 60);
            fs[idx] = actionsField;
            setFields(fs);
        }
    }
}
